{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "5c589c8b-46f3-4df7-bd3b-6baae2a63bdb",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import ConversationalRetrievalChain\n",
    "from langchain.memory import ConversationBufferMemory\n",
    "from langchain_community.document_loaders import TextLoader\n",
    "from langchain_community.vectorstores import FAISS\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_openai.embeddings import OpenAIEmbeddings\n",
    "from langchain_text_splitters import RecursiveCharacterTextSplitter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "35a2fb84-2d95-4db8-b896-77422e8f938b",
   "metadata": {},
   "outputs": [],
   "source": [
    "loader = TextLoader(\"./demo2.txt\")\n",
    "docs = loader.load()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "1806cd71-6ed2-43a2-a3fa-a2d3be393243",
   "metadata": {},
   "outputs": [],
   "source": [
    "text_splitter = RecursiveCharacterTextSplitter(\n",
    "    chunk_size=500,\n",
    "    chunk_overlap=40,\n",
    "    separators=[\"\\n\", \"。\", \"！\", \"？\", \"，\", \"、\", \"\"]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "bc3db8f3-bb5b-4484-9209-632dccfb9f68",
   "metadata": {},
   "outputs": [],
   "source": [
    "texts = text_splitter.split_documents(docs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "01597bf7-0851-4d22-830a-8427687cd12c",
   "metadata": {},
   "outputs": [],
   "source": [
    "embeddings_model = OpenAIEmbeddings()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "3d1e1cf4-7623-4d09-87ce-77bae9057aca",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "db = FAISS.from_documents(texts, embeddings_model)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "7867aa87-9e97-44ae-bb9a-500d4cd6e080",
   "metadata": {},
   "outputs": [],
   "source": [
    "retriever = db.as_retriever()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "9e284b73-afe2-49b2-94ce-d2e8b0850051",
   "metadata": {},
   "outputs": [],
   "source": [
    "model = ChatOpenAI(model=\"gpt-3.5-turbo\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "af994c92-8a5b-4d8d-9af3-96e30663c21a",
   "metadata": {},
   "outputs": [],
   "source": [
    "memory = ConversationBufferMemory(return_messages=True, memory_key='chat_history', output_key='answer')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "e8347d14-8fb5-4010-ad7b-ab2931096048",
   "metadata": {},
   "outputs": [],
   "source": [
    "qa = ConversationalRetrievalChain.from_llm(\n",
    "    llm=model,\n",
    "    retriever=retriever,\n",
    "    memory=memory\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "92a8b9d2-d2d3-46b8-b1d4-3c22c14a2664",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'chat_history': [HumanMessage(content='卢浮宫这个名字怎么来的？'),\n",
       "  AIMessage(content='根据法国百科全书辞典大拉鲁斯百科全书（Grand Larousse encyclopédique）的说法，\"罗浮宫\"这个名字来源于与狼狩猎巢穴的联系（拉丁语：lupus，下帝国：lupara）。')],\n",
       " 'question': '卢浮宫这个名字怎么来的？',\n",
       " 'answer': '根据法国百科全书辞典大拉鲁斯百科全书（Grand Larousse encyclopédique）的说法，\"罗浮宫\"这个名字来源于与狼狩猎巢穴的联系（拉丁语：lupus，下帝国：lupara）。'}"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "question = \"卢浮宫这个名字怎么来的？\"\n",
    "qa.invoke({\"chat_history\": memory, \"question\": question})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "d1ff96c3-ae23-4c0a-acd5-a5f3b4f61047",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'chat_history': [HumanMessage(content='卢浮宫这个名字怎么来的？'),\n",
       "  AIMessage(content='根据法国百科全书辞典大拉鲁斯百科全书（Grand Larousse encyclopédique）的说法，\"罗浮宫\"这个名字来源于与狼狩猎巢穴的联系（拉丁语：lupus，下帝国：lupara）。'),\n",
       "  HumanMessage(content='对应的拉丁语是什么呢？'),\n",
       "  AIMessage(content='这个名字对应的拉丁语是\"lupus\"。')],\n",
       " 'question': '对应的拉丁语是什么呢？',\n",
       " 'answer': '这个名字对应的拉丁语是\"lupus\"。'}"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "question = \"对应的拉丁语是什么呢？\"\n",
    "qa.invoke({\"chat_history\": memory, \"question\": question})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "d9ad371c-12cd-4fb2-a656-4a0c7521f777",
   "metadata": {},
   "outputs": [],
   "source": [
    "qa = ConversationalRetrievalChain.from_llm(\n",
    "    llm=model,\n",
    "    retriever=retriever,\n",
    "    memory=memory,\n",
    "    return_source_documents=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "d4f08717-5dfa-41fe-ac1a-29cf32f1ef78",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'chat_history': [HumanMessage(content='卢浮宫这个名字怎么来的？'),\n",
       "  AIMessage(content='根据法国百科全书辞典大拉鲁斯百科全书（Grand Larousse encyclopédique）的说法，\"罗浮宫\"这个名字来源于与狼狩猎巢穴的联系（拉丁语：lupus，下帝国：lupara）。'),\n",
       "  HumanMessage(content='对应的拉丁语是什么呢？'),\n",
       "  AIMessage(content='这个名字对应的拉丁语是\"lupus\"。'),\n",
       "  HumanMessage(content='卢浮宫这个名字怎么来的？'),\n",
       "  AIMessage(content='这个名字对应的拉丁语是lupus。')],\n",
       " 'question': '卢浮宫这个名字怎么来的？',\n",
       " 'answer': '这个名字对应的拉丁语是lupus。',\n",
       " 'source_documents': [Document(page_content='“罗浮宫”这个名字的由来有些争议。根据法国百科全书辞典大拉鲁斯百科全书（Grand Larousse encyclopédique）的说法，这个名字来源于与狼狩猎巢穴的联系（拉丁语：lupus，下帝国： lupara）。[6]此后好几个世纪，罗浮宫发生了很大变化。14世纪，法王查理五世觉得罗浮宫堡比位于塞纳河当中之城岛（西岱岛）的西岱宫更适合居住，于是搬迁至此。在他之后的法国国王再度搬出罗浮宫，直至1546年，弗朗索瓦一世才成为居住在罗浮宫的第二位国王。弗朗索瓦一世除了曾从意大利购买了包括油画《蒙娜丽莎》在内的大量艺术品外，还将原始的中世纪建筑夷为平地，命令建筑师皮埃尔·勒柯按照文艺复兴风格对其加以改建，于1546年至1559年修建了今日罗浮宫建筑群最东端的卡利庭院。扩建工程一直持续到亨利二世登基。亨利二世去世后，王太后凯瑟琳·德·美第奇集中力量修建杜伊勒里宫及杜乐丽花园，对罗浮宫的扩建工作再度停止。\\n\\n\\n目前仅存的中世纪地下室内的原城堡护城河遗迹。', metadata={'source': './demo2.txt'}),\n",
       "  Document(page_content='21世纪\\n1995年，法国总统贾克·席哈克在其朋友、艺术品收藏家和经销商雅克·克恰什(Jacques Kerchache)的推荐下，有鉴在历史上许多国家与法国的深厚渊源。因此开始倡议全面保存、典藏及推广非洲、亚洲、美洲及大洋洲的原创艺术文物的计画，除了策划布朗利河岸博物馆外，还在罗浮宫规划1,400平方公尺的长期展厅（Pavillon des Sessions），并在2000年对外开放。\\n\\n2016年6月，因欧洲水灾连日大雨导致巴黎塞纳河水位暴涨，波及市区道路与电车轨道，罗浮宫紧急将珍贵的艺术品搬到地势较高的楼层。这是罗浮宫1993年经整修并重新开放以来，馆方首次采取这项预防措施，2019年，巴黎圣母院遭遇大火后，圣母院的艺术品荆棘圣冠及圣路易祭袍等，将暂时转移到本馆保管。[21]', metadata={'source': './demo2.txt'}),\n",
       "  Document(page_content='罗浮宫（法语：Musée du Louvre,英语 /ˈluːv(rə)/ ），正式名称为罗浮博物馆，位于法国巴黎市中心的塞纳河边，原是建于12世纪末至13世纪初的王宫，现在是一所综合博物馆，亦是世界上最大的艺术博物馆之一，以及参观人数最多的博物馆，是巴黎中心最知名的地标。\\n\\n罗浮宫的建筑物始建于1190年左右，并在近代曾多次进行扩建，今天所见的模样则一个巨大的翼楼和亭阁建筑群，主要组成部分的总面积则超过60,600平方公尺（652,000平方英尺），馆内永久收藏则包括雕塑、绘画、美术工艺及古代东方、古代埃及和古希腊罗马等7个分类，主要收藏1860年以前的艺术作品与考古文物，罗浮宫博物馆在1793年8月10日开幕起正式对公众开放，平均每天有15,000名游客到此参观，其中65%是外国游客。[3]\\n\\n位置\\n\\n罗浮宫与杜乐丽花园的卫星照片\\n罗浮宫博物馆位于巴黎市中心的卢浮宫内，位于塞纳河右岸，毗邻杜乐丽花园。最近的两个地铁站是皇家宫-罗浮宫站和卢浮-里沃利站，前者有直达地下购物中心 Carrousel du Louvre 的地下通道。[4]', metadata={'source': './demo2.txt'}),\n",
       "  Document(page_content='莱斯科特翼在路易十三时期时随著扩建莱默西尔翼(9) 而向北扩展，在路易十四统治期间则扩大了小画廊 (10, 13)，其馀的翼栋则围绕方阁 (12, 16) 所建成，直到19世纪在拿破仑的统治下才完全完工。 拿破仑在卡鲁索广场规划了卡鲁索凯旋门 (17) 和增建北翼 (17) ，后来路易十八则再度扩展了北翼栋 (18) ，在1852 年到 1857年期间，拿破仑三世则建造了黎塞留翼（19）好将北翼与广场法院周围的建筑连接起来，并将天龙翼（19，南侧）与大画廊进行扩大。 1861年至1870年，建筑师赫克托尔·勒菲埃尔进行花神馆和大画廊 (7) 的改建工程，并设置了会议馆 (20)，最终在1874-1880 年完工从马森馆 (15) 到相邻的马森翼 (21) 的南立面工程。', metadata={'source': './demo2.txt'})]}"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "question = \"卢浮宫这个名字怎么来的？\"\n",
    "qa.invoke({\"chat_history\": memory, \"question\": question})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "64ddd438-65ac-438c-899e-bd86fc4c6520",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
